package com.dhcc.utils;

import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.JarURLConnection;
import java.net.URL;
import java.net.URLDecoder;
import java.util.Enumeration;
import java.util.LinkedList;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

/**
 * 类文件扫描
 * 
 * @author hibean@qq.com 2017年6月27日
 *
 */
public class ClassScanner {
	private List<String> classNames = new LinkedList<String>();
	public List<String> getClassNames() {
		return classNames;
	}
	public void scan(String packageName) {
		// 获取包的名字 并进行替换
		String packageDirName = packageName.replace('.', '/');
		// 定义一个枚举的集合 并进行循环来处理这个目录下的things
		Enumeration<URL> dirs = null;
		try {
			dirs = Thread.currentThread().getContextClassLoader()
					.getResources(packageDirName);
			// 循环迭代下去
			while (dirs.hasMoreElements()) {
				// 获取下一个元素
				URL url = dirs.nextElement();
				// 得到协议的名称
				String protocol = url.getProtocol();
				// 如果是以文件的形式保存在服务器上
				if ("file".equals(protocol)) {
					scanFile( packageName, url);
				} else if ("jar".equals(protocol)) {
					scanJar(packageDirName, url);
				}
			}
		} catch (IOException e) {
			System.err.println("扫描出错");
			e.printStackTrace();
		}
	}
	
	/**
	 * 扫描文件中的class文件
	 * @param pkg
	 * @param url
	 * @throws UnsupportedEncodingException
	 */
	private void scanFile(String pkg, URL url) throws UnsupportedEncodingException {
		String filePath = URLDecoder.decode(url.getFile(), "UTF-8");
		File dir = new File(filePath);
		File[] dirfiles = dir.listFiles();
		for (File file : dirfiles) {
			if (file.isFile()) {
				String fileName = file.getName();
				if(fileName.endsWith(".class")){
					String className = fileName.substring(0, fileName.length() - 6);
					classNames.add(pkg+"."+className);
				}
			}
		}
	}

	/**
	 * 扫描jar包中的类
	 * @param result
	 * @param packageDirName
	 * @param url
	 */
	private void scanJar(String packageDirName, URL url) {
		// 如果是jar包文件
		// 定义一个JarFile
		JarFile jar = null;
		try {
			// 获取jar
			jar = ((JarURLConnection) url.openConnection())
					.getJarFile();
			// 从此jar包 得到一个枚举类
			Enumeration<JarEntry> entries = jar.entries();
			// 同样的进行循环迭代
			while (entries.hasMoreElements()) {
				// 获取jar里的一个实体 可以是目录 和一些jar包里的其他文件 如META-INF等文件
				JarEntry entry = entries.nextElement();
				String name = entry.getName();
				// 如果是以/开头的
				if (name.charAt(0) == '/') {
					// 获取后面的字符串
					name = name.substring(1);
				}
				// 如果前半部分和定义的包名相同
				if (name.startsWith(packageDirName)) {
					int idx = name.lastIndexOf('/');
					// 如果以"/"结尾 是一个包
					if (idx==packageDirName.length() && name.endsWith(".class") && !entry.isDirectory()) {
						// 去掉后面的".class" 获取真正的类名
						String className = name.substring(0, name.length() - 6);
						classNames.add(className.replace('/', '.'));
					}
				}
			}
		} catch (IOException e) {
			System.err.println("在扫描用户定义视图时从jar包获取文件出错");
			e.printStackTrace();
		}
	}
}
